package com.gitee.feizns.webtemplate.commons.session;

import com.gitee.feizns.webtemplate.commons.utils.RequestUtils;
import com.gitee.feizns.webtemplate.commons.utils.encryption.EncryptUtils;

import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;

/**
 * @author feizns
 * @since 2019/4/10
 */
public class MapSessionManagerImpl implements SessionManager {

    /**
     * 会话有效时间
     */
    private int timeout;

    /**
     * 所有的会话
     */
    private HashMap<String, Session> sessions;

    /**
     * 会话键值生成策略
     */
    private TokenGenerator tokenGenerator;

    private Timer timer = new Timer(true);

    public MapSessionManagerImpl(int timeout, TokenGenerator keyGenerator, int initSize) {
        this.timeout = timeout;
        this.tokenGenerator = keyGenerator;
        this.sessions = new HashMap<>(initSize);
    }

    /**
     * 创建会话
     * @return
     */
    @Override
    public Session createSession() {
        String ip = RequestUtils.getIpAddress();
        String token = tokenGenerator.generator();
        String sessionKey = getKey(token, ip);
        MapSessionImpl session = new MapSessionImpl(token, timeout, ip);
        sessions.put(sessionKey, session);
        return session;
    }

    /**
     * 获取会话
     * @param token
     * @return
     */
    @Override
    public Session getSession(String token) {
        Session session = sessions.get(getKey(token, RequestUtils.getIpAddress()));
        if ( session != null )
            session.refresh();
        return session;
    }

    private String getKey(String token, String ip) {
        return EncryptUtils.sha_1(token + ip);
    }

    /**
     * 会话超时自动销毁
     */
    private class TimeOutInvalidate extends TimerTask {

        private Session session;

        public TimeOutInvalidate(Session session) {
            this.session = session;
            this.start();
        }

        @Override
        public void run() {
            session.invalidate();
        }

        public void start() {
            timer.schedule(this, timeout);
        }

    }

    /**
     *
     */
    private class MapSessionImpl extends AbstractSession {

        private TimerTask task;

        /**
         * 结束时间
         */
        private long endTime;

        /**
         * 有效时长
         */
        private int timeout;

        /**
         * 当前会话的ip
         */
        private String ip;

        public MapSessionImpl(String token, int timeout, String ip) {
            super(token);

            this.timeout = timeout;
            this.ip = ip;

            //启动定时销毁
            refresh();
        }

        @Override
        public long getExtraTime() {
            return endTime - System.currentTimeMillis();
        }

        /**
         * 替换定时任务的结束时间
         */
        @Override
        public void refresh() {

            endTime = System.currentTimeMillis() + timeout;

            //重启定时
            restartTime(new TimeOutInvalidate(this));
        }

        @Override
        public void invalidate() {
            restartTime(null);
            String key = getKey(getToken(), ip);
            sessions.remove( key );
            super.invalidate();
        }

        /**
         * 使用新任务重新开始计时
         * @param task
         */
        private void restartTime(TimerTask task) {
            if ( this.task != null )
                this.task.cancel();
            this.task = task;
        }

    }


}
